use crate::errors::error_level::ErrorLevel;
use crate::errors::errorkind::ErrorKind;
use std::fmt;

/// 编译器错误结构
#[derive(Debug, Clone)]
pub struct CompilerError {
    pub kind: ErrorKind,
    pub level: ErrorLevel,
    pub message: String,
    pub description: Option<String>, // 错误详细描述
    pub file_path: String,
    pub line: usize,
    pub column: usize,
    pub line_content: String,
    pub context: Option<String>,     // 相关上下文信息
    pub suggestion: Option<String>,  // 错误建议
    pub note: Option<String>,        // 附加说明
    pub span_length: Option<usize>,  // 标注长度
}

impl CompilerError {
    pub fn new(
        kind: ErrorKind,
        message: String,
        file_path: String,
        line: usize,
        column: usize,
        line_content: String,
    ) -> Self {
        CompilerError {
            kind,
            level: ErrorLevel::Error,
            message,
            description: None,
            file_path,
            line,
            column,
            line_content,
            context: None,
            suggestion: None,
            note: None,
            span_length: None,
        }
    }
    
    // 简化的构造函数，用于类型检查器等没有完整位置信息的情况
    pub fn simple(kind: ErrorKind, message: String) -> Self {
        CompilerError {
            kind,
            level: ErrorLevel::Error,
            message,
            description: None,
            file_path: "unknown".to_string(),
            line: 0,
            column: 0,
            line_content: "".to_string(),
            context: None,
            suggestion: None,
            note: None,
            span_length: None,
        }
    }

    /// 添加详细描述
    pub fn with_description(mut self, description: String) -> Self {
        self.description = Some(description);
        self
    }

    /// 添加上下文信息
    pub fn with_context(mut self, context: String) -> Self {
        self.context = Some(context);
        self
    }

    /// 添加建议
    pub fn with_suggestion(mut self, suggestion: String) -> Self {
        self.suggestion = Some(suggestion);
        self
    }

    /// 添加说明
    pub fn with_note(mut self, note: String) -> Self {
        self.note = Some(note);
        self
    }

    /// 设置标注长度
    pub fn with_span_length(mut self, length: usize) -> Self {
        self.span_length = Some(length);
        self
    }

    /// 设置错误级别
    pub fn with_level(mut self, level: ErrorLevel) -> Self {
        self.level = level;
        self
    }
}

impl fmt::Display for CompilerError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // 第一行：错误级别[错误代码]: 错误消息
        writeln!(
            f,
            "{}[{}]: {}",
            self.level.as_str(),
            self.kind.code(),
            self.message
        )?;

        // 第二行：文件位置
        writeln!(f, "  --> {}:{}:{}", self.file_path, self.line, self.column)?;

        // 分隔线
        writeln!(f, "   |")?;

        // 显示代码行
        let line_num_width = format!("{}", self.line).len();
        writeln!(
            f,
            " {:width$} | {}",
            self.line,
            self.line_content.trim_end(),
            width = line_num_width
        )?;

        // 标注错误位置
        let spaces = " ".repeat(self.column - 1);
        let carets = if let Some(len) = self.span_length {
            "^".repeat(len.max(1))
        } else {
            "^^^".to_string()
        };
        writeln!(
            f,
            " {:width$} | {}{}",
            "",
            spaces,
            carets,
            width = line_num_width
        )?;

        // 如果有上下文信息，显示上下文
        if let Some(ref context) = self.context {
            writeln!(f, "   |")?;
            writeln!(f, "   | {}", context)?;
        }

        // 如果有建议，显示建议
        if let Some(ref suggestion) = self.suggestion {
            writeln!(f, "   |")?;
            writeln!(f, "   = 帮助: {}", suggestion)?;
        }

        // 如果有详细描述，显示描述
        if let Some(ref description) = self.description {
            writeln!(f, "   |")?;
            writeln!(f, "   = 描述: {}", description)?;
        }

        // 如果有说明，显示说明
        if let Some(ref note) = self.note {
            writeln!(f, "   |")?;
            writeln!(f, "   = 说明: {}", note)?;
        }

        Ok(())
    }
}

impl std::error::Error for CompilerError {
    // 这个trait的方法已经有默认实现，我们可以不提供额外的实现
}
